package cz.uvn.orthopedy.client.ui.controller;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;

import cz.uvn.orthopedy.client.ApplicationController;
import cz.uvn.orthopedy.client.entity.Operation;
import cz.uvn.orthopedy.client.entity.ScheduleEntry;
import cz.uvn.orthopedy.client.ui.UIUtils;

public class ScheduleController implements PanelController, ClickHandler {
	
	public static final String[] TABLE_HEADER = {"Owner", "Day", "Hall", "Type", "Operation Type", "Edit", "Remove"}; 
	
	private ApplicationController controller;
	
	private VerticalPanel panel;
	private FlexTable table;
	private Button addButton;

	public ScheduleController(ApplicationController controller) {
		this.controller = controller;
		initUI();
	}

	private void initUI() {
		panel = new VerticalPanel();
		panel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);

		table = new FlexTable();
		table.addStyleName("table");
		initTable(0);
		panel.add(table);
		
		addButton = new Button("Add...");
		addButton.addClickHandler(this);
		panel.add(addButton);
	}

	@Override
	public Panel getView() {
		return panel;
	}
	
	@Override
	public void refresh() {
		load();
	}

	@Override
	public void onClick(ClickEvent event) {
		Object source = event.getSource();
		if (source == addButton) {
			showEditDialog(null);
		}
	}
	
	private void initTable(int rows) {
		table.clear(true);
		table.setSize(String.valueOf(TABLE_HEADER.length), String.valueOf(rows + 1));
		table.setCellPadding(TABLE_HEADER.length);
		for (int i = 0; i < TABLE_HEADER.length; i++) {
			table.setText(0, i, TABLE_HEADER[i]);
		}
		table.getRowFormatter().addStyleName(0, "tableHeader");
	}
	
	private void displayEntries(final ScheduleEntry[] entries) {
		initTable(entries.length);
		for (int i = 0; i < entries.length; i++) {
			final ScheduleEntry entry = entries[i];
			
			String owner = entry.getOwnerId() != null ? 
					controller.getDoctorByID(entry.getOwnerId()).toString() : "<unknown>";
			table.setText(i + 1, 0, owner);
			table.setText(i + 1, 1, controller.dayToString(entry.getDay()));
			table.setText(i + 1, 2, controller.getHallByID(entry.getHallId()).toString());
			table.setText(i + 1, 3, entry.getType().toString());
			table.setText(i + 1, 4, entry.getOperationType().toString());
			
			Button editButton = new Button("...");
//			editButton.addStyleDependentName("edit");
			editButton.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					showEditDialog(entry);
				}
			});
			table.setWidget(i + 1, 5, editButton);
			
			Button removeButton = new Button("x");
//			removeButton.addStyleDependentName("remove");
			removeButton.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					remove(entry);
				}
			});
			table.setWidget(i + 1, 6, removeButton);
		}
	}

	private void showEditDialog(final ScheduleEntry entry) {
		final DialogBox dialogBox = new DialogBox();
//		dialogBox.setWidth("200px");
//		dialogBox.addStyleName("dialogBox");
		dialogBox.setText(entry == null ? "Add new Schedule Entry" : "Edit Schedule Entry");
		dialogBox.setAnimationEnabled(true);
		
		final ListBox ownersBox = new ListBox(false);
		for (int i = 0; i < controller.getDoctorsCache().length; i++) {
			ownersBox.addItem(controller.getDoctorsCache()[i].toString());
		}
		ownersBox.addItem("<unknown>");
		ownersBox.setVisibleItemCount(1);
		
		final ListBox daysBox = new ListBox(false);
		daysBox.addItem("Sunday");
		daysBox.addItem("Monday");
		daysBox.addItem("Tuesday");
		daysBox.addItem("Wednesday");
		daysBox.addItem("Thursday");
		daysBox.addItem("Friday");
		daysBox.addItem("Saturday");
		daysBox.setVisibleItemCount(1);

		final ListBox hallsBox = new ListBox(false);
		for (int i = 0; i < controller.getHallsCache().length; i++) {
			hallsBox.addItem(controller.getHallsCache()[i].toString());
		}
		hallsBox.setVisibleItemCount(1);
		
		final ListBox typesBox = new ListBox(false);
		for (ScheduleEntry.Type type : ScheduleEntry.Type.values()) {
			typesBox.addItem(type.toString());
		}
		typesBox.setVisibleItemCount(1);
		typesBox.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				ScheduleEntry.Type type = ScheduleEntry.Type.values()[typesBox.getSelectedIndex()];
				ownersBox.setEnabled(type != ScheduleEntry.Type.General);
			}
		});
		
		final ListBox opTypesBox = new ListBox(false);
		for (Operation.Type opType : Operation.Type.values()) {
			opTypesBox.addItem(opType.toString());
		}
		opTypesBox.setVisibleItemCount(1);
		
		if (entry != null) {
			int index = 0;
			if (entry.getOwnerId() == null) { // <unknown>
				index = controller.getDoctorsCache().length;
			} else {
				for (int i = 0; i < controller.getDoctorsCache().length; i++) {
					if (controller.getDoctorsCache()[i].getId().equals(entry.getOwnerId())) {
						index = i;
						break;
					}
				}
			}
			ownersBox.setSelectedIndex(index);
			
			daysBox.setSelectedIndex(entry.getDay());

			index = 0;
			for (int i = 0; i < controller.getHallsCache().length; i++) {
				if (controller.getHallsCache()[i].getId().equals(entry.getHallId())) {
					index = i;
					break;
				}
			}
			hallsBox.setSelectedIndex(index);
			
			index = 0;
			for (int i = 0; i < ScheduleEntry.Type.values().length; i++) {
				if (ScheduleEntry.Type.values()[i].equals(entry.getType())) {
					index = i;
					break;
				}
			}
			typesBox.setSelectedIndex(index);
			
			index = 0;
			for (int i = 0; i < Operation.Type.values().length; i++) {
				if (Operation.Type.values()[i].equals(entry.getOperationType())) {
					index = i;
					break;
				}
			}
			opTypesBox.setSelectedIndex(index);
		}

		final Button okButton = new Button("OK");
		okButton.getElement().setId("dialogButton");
		okButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				Long ownerId = null;
				if (ownersBox.isEnabled()) {
					int index = ownersBox.getSelectedIndex();
					if (index < controller.getDoctorsCache().length) {
						ownerId = controller.getDoctorsCache()[ownersBox.getSelectedIndex()].getId();
					}// else <unknown>
				}
				
				int day = daysBox.getSelectedIndex();
				Long hallId = controller.getHallsCache()[hallsBox.getSelectedIndex()].getId();
				ScheduleEntry.Type type = ScheduleEntry.Type.values()[typesBox.getSelectedIndex()];
				Operation.Type opType = Operation.Type.values()[opTypesBox.getSelectedIndex()];
				
				if (entry == null) {
					ScheduleEntry e = new ScheduleEntry();
					e.setOwnerId(ownerId);
					e.setDay(day);
					e.setHallId(hallId);
					e.setType(type);
					e.setOperationType(opType);
					edit(e);
				} else {
					entry.setOwnerId(ownerId);
					entry.setDay(day);
					entry.setHallId(hallId);
					entry.setType(type);
					entry.setOperationType(opType);
					edit(entry);
				}
				dialogBox.hide();
			}
		});

		final Button cancelButton = new Button("Cancel");
		cancelButton.getElement().setId("dialogButton");
		cancelButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogBox.hide();
			}
		});

		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(new HTML("<b>Owner:</b>"));
		dialogVPanel.add(ownersBox);
		dialogVPanel.add(new HTML("<br><b>Day:</b>"));
		dialogVPanel.add(daysBox);
		dialogVPanel.add(new HTML("<br><b>Hall:</b>"));
		dialogVPanel.add(hallsBox);
		dialogVPanel.add(new HTML("<br><b>Type:</b>"));
		dialogVPanel.add(typesBox);
		dialogVPanel.add(new HTML("<br><b>Operation Type:</b>"));
		dialogVPanel.add(opTypesBox);
		
		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		HorizontalPanel dialogHPanel = new HorizontalPanel();
		dialogHPanel.add(okButton);
		dialogHPanel.add(cancelButton);
		dialogVPanel.add(dialogHPanel);
		
		dialogBox.setWidget(dialogVPanel);
		dialogBox.center();
		ownersBox.setFocus(true);
	}

	private void load() {
		controller.getJournalService().getScheduleEntries(new AsyncCallback<ScheduleEntry[]>() {
			@Override
			public void onSuccess(final ScheduleEntry[] entries) {
				displayEntries(entries);
			}
			@Override
			public void onFailure(Throwable error) {
				UIUtils.handleError(error);
			}
		});
	}
	
	private void edit(final ScheduleEntry entry) {
		if (entry.getId() == null) {
			controller.getJournalService().createScheduleEntry(entry, new AsyncCallback<Void>() {
				@Override
				public void onSuccess(Void ignore) {
					load();
				}
				@Override
				public void onFailure(Throwable error) {
					UIUtils.handleError(error);
				}
			});
		} else {
			controller.getJournalService().editScheduleEntry(entry, new AsyncCallback<Void>() {
				@Override
				public void onSuccess(Void ignore) {
					load();
				}
				@Override
				public void onFailure(Throwable error) {
					UIUtils.handleError(error);
				}
			});
		}
	}

	private void remove(final ScheduleEntry entry) {
		controller.getJournalService().deleteScheduleEntry(entry, new AsyncCallback<Void>() {
			@Override
			public void onSuccess(Void ignore) {
				load();
			}
			@Override
			public void onFailure(Throwable error) {
				UIUtils.handleError(error);
			}
		});
	}
}
